
#include <BFont>
#include <BIcon>
#include <BPainter>
#include <BMouseEvent>
#include <BMenuBar>
#include "member_BMenuBar.h"

using namespace BWE;

#define member					(*(member_BMenuBar*)_ptr)
#define member_allocate()		_ptr = new member_BMenuBar(this)
#define member_release()		delete (member_BMenuBar*)_ptr

BMenuBar::BMenuBar(BWidget* parent) : BWidget(parent)
{
	member_allocate();
}
BMenuBar::~BMenuBar()
{
	member_release();
}

void BMenuBar::setAlign(Align align)
{
	if (member.align != align)
	{
		member.align = align;
		member.dirty = true;
		this->fresh();
	}
}
Align BMenuBar::align() const
{
	return member.align;
}

void BMenuBar::setForm(Form form)
{
	if (member.form != form)
	{
		member.form = form;
		member.dirty = true;
		this->fresh();
	}
}
Form BMenuBar::form() const
{
	return member.form;
}

void BMenuBar::setOrientation(Orientation orientation)
{
	if (member.orientation != orientation)
	{
		member.orientation = orientation;
		member.dirty = true;
	}
}
Orientation BMenuBar::orientation() const
{
	return member.orientation;
}

void BMenuBar::setSpacing(int spacing)
{
	if (member.spacing != spacing)
	{
		member.spacing = spacing;
		member.dirty = true;
		this->fresh();
	}
}
int BMenuBar::spacing() const
{
	return member.spacing;
}

void BMenuBar::addMenu(BMenu* menu)
{
	if (this->contain(menu))
		return;
	this->addChild(menu);
	menu->hide();
	member.items.append(menu);
	member.connect(menu, Signal_Enabled, &member_BMenuBar::slotMenuAbleChanged);
	member.connect(menu, Signal_TitleChanged, &member_BMenuBar::slotTitleChanged);
	member.connect(menu, Signal_TitleIconChanged, &member_BMenuBar::slotTitleIconChanged);
	member.dirty = true;
	this->fresh();
}
BMenu* BMenuBar::addMenu(const BString& title)
{
	for (int i = 0; i < member.items.size(); i++)
	{
		if (member.items[i].menu->title() == title)
			return 0;
	}
	BMenu* menu = new BMenu(title);
	addMenu(menu);
	return menu;
}

void BMenuBar::insertMenu(int index, BMenu* menu)
{
	if (!this->contain(menu))
	{
		this->addChild(menu);
		menu->hide();
		member.items.insert(index, menu);
		member.connect(menu, Signal_TitleChanged, &member_BMenuBar::slotTitleChanged);
		member.connect(menu, Signal_TitleIconChanged, &member_BMenuBar::slotTitleIconChanged);
		member.dirty = true;
		this->fresh();
	}
}
BMenu* BMenuBar::insertMenu(int index, const BString& title)
{
	if (index < 0)
		return 0;
	for (int i = 0; i < member.items.size(); i++)
	{
		if (member.items[i].menu->title() == title)
			return 0;
	}
	BMenu* menu = new BMenu(title);
	insertMenu(index, menu);
	return menu;
}

bool BMenuBar::removeMenu(BMenu* menu)
{
	if (member.items.remove(menu))
	{
		this->removeChild(menu);
		member.disconnect(menu);
		member.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BMenuBar::clearMenus()
{
	if (member.items.size())
	{
		while (member.items.size())
		{
			MenuBarItem& last = member.items.last();
			if (last.menu)
			{
				this->removeChild(last.menu);
				member.disconnect(last.menu);
			}
			member.items.remove(member.items.size() - 1);
		}
		member.dirty = true;
		this->fresh();
	}
	return true;
}

BSize BMenuBar::sizeHint() const
{
	if (member.dirty)
		member.freshRects();
	BSize csize = member.contentSize;
	BSize hsize = BWidget::sizeHint();
	return hsize + csize;
}

void BMenuBar::resizeEvent(const BEvent& event)
{
	member.dirty = true;
}

void BMenuBar::styleEvent(const BEvent& event)
{
	for (int i = 0; i < member.items.size(); i++)
	{
		member.items[i].dirty = true;
	}
	member.dirty = true;
}
void BMenuBar::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.freshRects();
	}
}
void BMenuBar::paintEvent(const BEvent& event)
{
	BRect crect = this->centerRect();

	BPainter painter(this);
	painter.drawBackground();

	for(int i = 0; i < member.items.size(); i++)
	{
		const MenuBarItem& item = member.items[i];
		const BRect& rect = item.rect;
		const BMenu* menu = item.menu;

		if (menu->enabled() == false)
		{
			painter.setColor(Color_Background_Disable);
			painter.fillRect(rect);
		}
		else if (member.hoverIndex == i)
		{
			if (member.pressed)
				painter.setColor(Color_Background_Pressed);
			else
				painter.setColor(Color_Background_Hovered);
			painter.fillRect(rect);
		}

		BIcon* titleIcon = item.menu->titleIcon();
		if (titleIcon)
		{
			BImage* image = titleIcon->image(State_Normal);
			if (menu->enabled() == false)
			{
				image = titleIcon->image(State_Disable);
			}
			else if (member.hoverIndex == i)
			{
				if (member.pressed)
					image = titleIcon->image(State_Pressed);
				else
					image = titleIcon->image(State_Hovered);
			}
			painter.drawImage(item.iconRect, image);
		}

		painter.setColor(Color_Text);
		if (menu->enabled() == false)
		{
			painter.setColor(Color_Text_Disable);
		}
		else if (member.hoverIndex == i)
		{
			if (member.pressed)
				painter.setColor(Color_Text_Pressed);
			else
				painter.setColor(Color_Text_Hovered);
		}
		if (item.t_title.size())
			painter.drawText(item.textRect, item.t_title);
		else
			painter.drawText(item.textRect, menu->title());
	}
	painter.drawPerch();
	painter.drawMargin();
	painter.drawBorder();
}

void BMenuBar::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.hoverIndex = -1;
}
void BMenuBar::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoverIndex != -1)
	{
		member.hoverIndex = -1;
		fresh();
	}
}

void BMenuBar::mousePressEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = true;
	this->fresh();
}
void BMenuBar::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = false;
	this->fresh();
}
void BMenuBar::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	int hoverIndex = -1;
	const BPoint& pos = mouseEvent.pos();
	for (int i = 0; i < member.items.size(); i++)
	{
		if (member.items[i].rect.contain(pos))
		{
			hoverIndex = i;
			break;
		}
	}
	if (member.hoverIndex != hoverIndex)
	{
		member.hoverIndex = hoverIndex;
		this->fresh();
	}
}

void BMenuBar::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoverIndex > -1)
	{
		BMenu* menu = member.items[member.hoverIndex].menu;
		if (menu->visible())
		{
			menu->hide();
		}
		else if(menu->enabled())
		{
			BRect& itemRect = member.items[member.hoverIndex].rect;
			BSize size = menu->sizeHint();
			BRect rootRect = this->mapFrom(this->root(), this->root()->size());
			BRect rect = this->rect();
			if (member.orientation == Orientation_Horizontal)
			{
				int spaceDown = rootRect.bottom() - rect.bottom();
				if (spaceDown < size.height())
				{
					menu->setPos(itemRect.left(), itemRect.top() - size.height());
				}
				else
				{
					menu->setPos(itemRect.left(), itemRect.bottom());
				}
				if (size.width() > rootRect.width())
					size.width() = rootRect.width();
				menu->setSize(size);
				menu->setParent(this);
				menu->popup();
			}
			if (member.orientation == Orientation_Vertical)
			{

			}

		}
		this->fresh();
	}
}
void BMenuBar::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{

}
